/* 部分参考contiki
 * Copyright (c) 2005, Swedish Institute of Computer Science
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the Contiki operating system.
 *
 */
/**
 * Copyright (c) 2006-2020, zwl
 * 
 * description  协程处理框架函数
 * 
 * Change Logs:
 * Date             Author         Notes
 * 2021-01-11       Zwl             创建
 * 
 */
#include "EntTypeFramework.h"


/* 当前正在执行的协程 */
struct etf_co_tcb *         etf_process_current                     = ETF_NULL;

/* 全局轮询标志 仅使用etf_process_poll置位，当这个标志置位后，才会轮询每个协程的poll标志 */
static volatile etf_uint8_t poll_requested_flag                     = 0;
/* 线程链表首地址 */
static volatile struct etf_object_information   *coroutine_information   = ETF_NULL;

/**
 *  协程模块初始化。使能协程的时候需要先初始化
 *
 *@param :
 *
 *@return:
 *
 *@note  : 
 *
 *
 */
void etf_coroutine_module_init(void){

    /* 从对象容器中获得对应类型的节点头(协程链表节点头) */
    coroutine_information                       = etf_object_get_information(ETF_Object_Class_Coroutine);
    ETF_IN_ASSERT(ETF_NULL != coroutine_information);
}

/**
 *  协程任务初始化，初始化协程控制块(创建协程任务)
 *
 *@param :  co_tcb      ：协程控制块指针；
 *          name        ：协程任务名；
 *          coroutine   ：协程处理函数指针；
 *
 *@return:  ETF_NULL    ：初始化失败；否则：返回协程控制块指针；
 *
 *@note  : 
 *
 *
 */
struct etf_co_tcb * etf_coroutine_init(struct etf_co_tcb * const co_tcb, const char *name, 
        etf_uint8_t (*coroutine)(struct pt * co_pt, coroutine_event_t co_ev, coroutine_data_t co_data)){

    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    ETF_IN_ASSERT(coroutine != ETF_NULL);

    /* 设置协程状态，挂起 */
    co_tcb->state                               = ETF_PROCESS_STATE_NONE;
    /* 设置线程行号未默认值0 */
    LC_INIT(co_tcb->pt.lc);
    /* 轮询请求传递的数据 */
    co_tcb->data                                = ETF_NULL;
    /* 设置协程任务函数 */
    co_tcb->coroutine                           = coroutine;
    /* 设置轮询请求0，不启动 */
    co_tcb->needspoll                           = 0;
    
    /* 初始化协程节点，并插入对象容器相应的链表中 */
    etf_object_init(&(co_tcb->parent), ETF_Object_Class_Coroutine, name);

    return co_tcb;
}

/**
 *  协程启动
 *
 *@param :  co_tcb      ：协程控制块指针；
 *
 *@return:  结果；
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_coroutine_startup(struct etf_co_tcb * const co_tcb){

    struct etf_co_tcb *         co_tcb_old;
    
    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    ETF_IN_ASSERT(co_tcb != ETF_NULL);

    //检查传入的对象是否为协程类型
    ETF_IN_ASSERT( etf_object_get_type(&co_tcb->parent) == ETF_Object_Class_Coroutine);
    //检查传入的对象是否是系统对象(是否是已经注册到对象容器中的对象)
    if(ETF_FALSE == etf_object_is_systemobject(&co_tcb->parent)){
        return (-ETF_ERROR);
    }

    if(ETF_PROCESS_STATE_CALLED == co_tcb->state){
        return (-ETF_ERROR); 
    } else if(ETF_PROCESS_STATE_RUNNING == co_tcb->state){
        return ETF_EOK;
    }

    /* 转换到运行链表中 */
    if(ETF_EOK != etf_object_change_to_run_list(&(co_tcb->parent))){
        return (-ETF_ERROR);
    }

    /* 设置线程行号未默认值0 */
    LC_INIT(co_tcb->pt.lc);
    
    //运行模式
    co_tcb->state                           = ETF_PROCESS_STATE_RUNNING;

    /* 执行一次 */
    if(ETF_NULL != co_tcb->coroutine){
        co_tcb_old                          = etf_process_current;
        call_process(co_tcb, ETF_PROCESS_EVENT_INIT, ETF_NULL);
        etf_process_current                 = co_tcb_old;
//        co_tcb->coroutine(&(co_tcb->pt), ETF_PROCESS_EVENT_INIT, ETF_NULL);
    }
    
    return ETF_EOK;
}


/**
 *  删除注册的协程
 *
 *@param :  co_tcb      ：协程控制块指针；
 *
 *@return:  结果；
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_coroutine_unregister(struct etf_co_tcb * const co_tcb){

    struct etf_co_tcb *         co_tcb_old      = etf_process_current;
    
    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    ETF_IN_ASSERT(co_tcb != ETF_NULL);

    //检查传入的对象是否为协程类型
    ETF_IN_ASSERT( etf_object_get_type(&co_tcb->parent) == ETF_Object_Class_Coroutine);
    //检查传入的对象是否是系统对象(是否是已经注册到对象容器中的对象)
    if(ETF_FALSE == etf_object_is_systemobject(&co_tcb->parent)){
        etf_process_current                     = co_tcb_old;
        return (-ETF_ERROR);
    }

    //挂起
    co_tcb->state                               = ETF_PROCESS_STATE_NONE;
    
    //从对象容器中分离，解除注册
    etf_object_detach(&(co_tcb->parent));

    etf_process_current                         = co_tcb_old;
    return ETF_EOK;
}

/**
 *  协程挂起
 *
 *@param :  co_tcb：协程控制块指针；
 *
 *@return:  结果；
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_coroutine_suspend(struct etf_co_tcb * const co_tcb){

    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    ETF_IN_ASSERT(co_tcb != ETF_NULL);
            
    //检查传入的对象是否为协程类型
    ETF_IN_ASSERT(etf_object_get_type(&co_tcb->parent) == ETF_Object_Class_Coroutine);
    //检查传入的对象是否是系统对象(是否是已经注册到对象容器中的对象)
    if(ETF_FALSE == etf_object_is_systemobject(&co_tcb->parent)){
        return (-ETF_ERROR);
    }

    if(ETF_PROCESS_STATE_CALLED == co_tcb->state){
        return (-ETF_ERROR); 
    } else if(ETF_PROCESS_STATE_NONE == co_tcb->state){
        return ETF_EOK;
    }
    
    /* 转到挂起队列 */
    if(ETF_EOK != etf_object_change_to_suspend_list(&(co_tcb->parent)) ){
        return (-ETF_ERROR);
    }

    //挂起
    co_tcb->state                               = ETF_PROCESS_STATE_NONE;

    /* 设置线程行号未默认值0 */
    LC_INIT(co_tcb->pt.lc);
    /* 轮询请求传递的数据 */
    co_tcb->data                                = ETF_NULL;
    
    return ETF_EOK;
}

/**
 *  协程恢复
 *
 *@param :  co_tcb：协程控制块指针；
 *
 *@return:  结果；
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_coroutine_resume(struct etf_co_tcb * const co_tcb){

    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    ETF_IN_ASSERT(co_tcb != ETF_NULL);
            
    //检查传入的对象是否为协程类型
    ETF_IN_ASSERT(etf_object_get_type(&co_tcb->parent) == ETF_Object_Class_Coroutine);
    //检查传入的对象是否是系统对象(是否是已经注册到对象容器中的对象)
    if(ETF_FALSE == etf_object_is_systemobject(&co_tcb->parent)){
        return (-ETF_ERROR);
    }

    if(ETF_PROCESS_STATE_NONE != co_tcb->state){
        return (-ETF_ERROR); 
    }

    /* 设置线程行号未默认值0 */
    LC_INIT(co_tcb->pt.lc);
    /* 轮询请求传递的数据 */
    co_tcb->data                                = ETF_NULL;
    
    if(ETF_EOK != etf_object_change_to_run_list(&(co_tcb->parent))){
        return (-ETF_ERROR);
    }
    
    //运行模式
    co_tcb->state                               = ETF_PROCESS_STATE_RUNNING;
    
    return ETF_EOK;
}

/**
 *  轮询请求，轮询指定协程任务
 *
 *@param :  
 *
 *@return:
 *
 *@note  : 
 *
 *
 */
void etf_poll_requested(struct etf_co_tcb * const co_tcb, coroutine_data_t co_data){

    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    ETF_IN_ASSERT(co_tcb != ETF_NULL);

    if( (ETF_PROCESS_STATE_RUNNING == co_tcb->state) || (ETF_PROCESS_STATE_CALLED == co_tcb->state) ){
        /* 设置协程任务的轮询请求标志 */
        co_tcb->needspoll                       = 1;
        /* 数据 */
        co_tcb->data                            = co_data;
        /* 设置全区轮询请求标志 */
        poll_requested_flag                     = 1;
    }
}


/**
 *
 *
 *@param :  co_tcb：协程控制块指针；
 *
 *@return:
 *
 *@note  : 
 *
 *
 */
void call_process(struct etf_co_tcb * const co_tcb, coroutine_event_t co_ev, coroutine_data_t co_data){

    etf_uint8_t                     ret         = PRO_YIELDED;

    if( (ETF_PROCESS_STATE_RUNNING & co_tcb->state) && (ETF_NULL != co_tcb->coroutine) ){
    
        etf_process_current                     = co_tcb;
        /* 改变状态 */
        co_tcb->state                           = ETF_PROCESS_STATE_CALLED;
        /* 处理协程任务 */
        ret                                     = co_tcb->coroutine( &(co_tcb->pt), co_ev, co_data );

        if( (ret == PRO_EXITED) || (ret == PRO_ENDED) ){
            /* 如果返回值为退出，则删除注册的协程 */
            etf_coroutine_unregister(co_tcb);

        } else {
            /* 执行完成，改变状态 */
            co_tcb->state                       = ETF_PROCESS_STATE_RUNNING;
        }
    } 
}

/**
 *  协程轮训处理函数
 *
 *@param :
 *
 *@return:
 *
 *@note  : 
 *
 *
 */
static void do_poll(void){

    struct etf_co_tcb *                         p_co_tcb;
    struct etf_object *                         object;
    struct etf_list_node *                      node    = ETF_NULL;

    ETF_IN_ASSERT(coroutine_information != ETF_NULL);
    
    /* 全局轮询标志清零 */
    poll_requested_flag                                 = 0;

    /* 轮询协程，处理请求，通过对象容器中对应协程类型的链表轮询整个链表 */
    for(node = coroutine_information->object_run_list.next; node != &(coroutine_information->object_run_list); node = node->next){
        /* 获取节点对象的继承成员地址 */
        object                                          = etf_list_entry(node, struct etf_object, list);
        /* 继承的这个对象是结构中的第一个成员，直接进行类型转换 */
        p_co_tcb                                        = (struct etf_co_tcb *)object;

        if(p_co_tcb->needspoll){
            //有轮询请求，改变状态
            p_co_tcb->state                             = ETF_PROCESS_STATE_RUNNING;
            p_co_tcb->needspoll                         = 0;
            /* 调用协程处理函数，事件为轮询请求 */
            call_process(p_co_tcb, ETF_PROCESS_EVENT_POLL, p_co_tcb->data);
        }
    }
}

/**
 *  协程运行处理
 *
 *@param :
 *
 *@return: 是否还有处理请求
 *
 *@note  : 
 *
 *
 */
etf_uint32_t etf_coroutine_run(void){

    /* poll事件处理 */
    if(poll_requested_flag){
        do_poll();
    }

    return poll_requested_flag;
}















